package com.tyylab.kestrel.framework.spring.rpc.feign.impl;

import cn.hutool.core.util.StrUtil;
import com.tyylab.kestrel.framework.core.annoutil.SpringCoreAnnotationUtil;
import com.tyylab.kestrel.framework.core.build.DefaultClassBuilder;
import com.tyylab.kestrel.framework.core.build.IClassBuilder;
import com.tyylab.kestrel.framework.core.build.intf.IMethodAnnotatable;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;

/**
 * Generate Fallback classes for Feign clients
 * @author tyylab
 */
@Slf4j
public class FeignFallbackGenerator {
    
    /**
     * Generate fallback class for the given API interface
     * @param api the original API interface
     * @return generated fallback class
     */
    public Class<?> generateFallback(Class<?> api) {
        if (api == null || !api.isInterface()) {
            log.warn("Invalid API interface provided for fallback generation: {}", api);
            return null;
        }
        
        String fallbackClassName = api.getName() + "Fallback";
        String instanceName = StrUtil.lowerFirst(api.getSimpleName() + "Fallback");
        
        log.debug("Generating fallback class: {} for API: {}", fallbackClassName, api.getName());
        
        IClassBuilder classBuilder = new DefaultClassBuilder();
        
        // Define the fallback class
        classBuilder = classBuilder.defineClass()
                // .clazz(fallbackClassName, null, api)
                .clazz(fallbackClassName)
                .modifiers(Modifier.PUBLIC)
                .annotate(SpringCoreAnnotationUtil.component(instanceName))
                .end();
        
        // Generate methods for each interface method
        Method[] methods = api.getDeclaredMethods();
        for (Method method : methods) {
            classBuilder = generateFallbackMethod(classBuilder, method);
        }
        
        try {
            Class<?> fallbackClass = classBuilder.build();
            log.debug("Successfully generated fallback class: {}", fallbackClass.getName());
            return fallbackClass;
        } catch (Exception e) {
            log.error("Failed to generate fallback class for API: {}", api.getName(), e);
            return null;
        }
    }
    
    /**
     * Generate a fallback method implementation
     * @param classBuilder the class builder
     * @param method the original method
     * @return updated class builder
     */
    private IClassBuilder generateFallbackMethod(IClassBuilder classBuilder, Method method) {
        String methodName = method.getName();
        Type returnType = method.getGenericReturnType();
        
        log.debug("Generating fallback method: {} with return type: {}", methodName, returnType.getTypeName());
        
        // Start method definition
        IClassBuilder.IMethodDefine methodDefine = classBuilder.defineMethod()
                .method(methodName, returnType, Modifier.PUBLIC);
        
        // Add parameters
        Parameter[] parameters = method.getParameters();
        IClassBuilder.IParamDefine paramDefine = null;
        
        if (parameters != null && parameters.length > 0) {
            for (int i = 0; i < parameters.length; i++) {
                Parameter param = parameters[i];
                if (paramDefine == null) {
                    paramDefine = methodDefine.param(param.getName(), param.getType(), param.getModifiers());
                } else {
                    paramDefine = paramDefine.param(param.getName(), param.getType(), param.getModifiers());
                }
            }
            methodDefine = paramDefine.end();
        }
        
        // Implement the method with fallback logic
        IMethodAnnotatable<IClassBuilder.IMethodDefine> methodAnnotatable = methodDefine.impl()
                .delegate(EnhancedFeignFallbackInterceptor.class);
        
        methodAnnotatable.end();
        return classBuilder;
    }
} 